# -*- coding: utf-8 -*-
'''
Created on 29.07.2019

@author: yu03
'''

#!/usr/bin/env python

#------------------------------------------------------------------------------
#                 PyuEye example - camera modul
#
# Copyright (c) 2017 by IDS Imaging Development Systems GmbH.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#------------------------------------------------------------------------------
import ctypes
from pyueye import ueye
from PyUeye.IDS_lib.pyueye_utils import (uEyeException, Rect, get_bits_per_pixel,
                                  ImageBuffer, check)

class Camera:
    def __init__(self, device_id=0):
        self.h_cam = ueye.HIDS(device_id)
        self.img_buffers = []

    def __enter__(self):
        self.init()
        return self

    def __exit__(self, _type, value, traceback):
        self.exit()

    def handle(self):
        return self.h_cam

    def alloc(self, buffer_count=3):
        rect = self.get_aoi()
        bpp = get_bits_per_pixel(self.get_colormode())

        for buff in self.img_buffers:
            check(ueye.is_FreeImageMem(self.h_cam, buff.mem_ptr, buff.mem_id))

        for i in range(buffer_count):
            buff = ImageBuffer()
            ueye.is_AllocImageMem(self.h_cam,
                                  rect.width, rect.height, bpp,
                                  buff.mem_ptr, buff.mem_id)
            
            check(ueye.is_AddToSequence(self.h_cam, buff.mem_ptr, buff.mem_id))

            self.img_buffers.append(buff)

        ueye.is_InitImageQueue(self.h_cam, 0)

    def init(self):
        ret = ueye.is_InitCamera(self.h_cam, None)
        if ret != ueye.IS_SUCCESS:
            self.h_cam = None
            raise uEyeException(ret)
            
        return ret

    def exit(self):
        ret = None
        if self.h_cam is not None:
            ret = ueye.is_ExitCamera(self.h_cam)
        if ret == ueye.IS_SUCCESS:
            self.h_cam = None
    
    def get_FrameTimeRange(self):
        min = ueye.double()
        max = ueye.double()
        intervall = ueye.double()
        ueye.is_GetFrameTimeRange(self.h_cam, min, max, intervall)
        return min, max, intervall
    
    def get_fps(self):
        fps = ueye.double()
        ueye.is_GetFramesPerSecond(self.h_cam, fps)
        return fps
    
    def set_fps(self, fps):
        fps = ueye.double(fps)
        origin_fps = self.get_fps()
        return ueye.is_SetFrameRate(self.h_cam, fps, fps)
    
    def get_aoi(self):
        rect_aoi = ueye.IS_RECT()
        ueye.is_AOI(self.h_cam, ueye.IS_AOI_IMAGE_GET_AOI, rect_aoi, ueye.sizeof(rect_aoi))
        return Rect(rect_aoi.s32X.value,
                    rect_aoi.s32Y.value,
                    rect_aoi.s32Width.value,
                    rect_aoi.s32Height.value)

    def set_aoi(self, x, y, width, height):
        rect_aoi = ueye.IS_RECT()
        rect_aoi.s32X = ueye.int(x)
        rect_aoi.s32Y = ueye.int(y)
        rect_aoi.s32Width = ueye.int(width)
        rect_aoi.s32Height = ueye.int(height)
        return ueye.is_AOI(self.h_cam, ueye.IS_AOI_IMAGE_SET_AOI, rect_aoi, ueye.sizeof(rect_aoi))
        
    def set_external_trigger(self):
        return ueye.is_SetExternalTrigger(self.h_cam, ueye.IS_SET_TRIGGER_HI_LO)
    
    def get_flash_mode(self):
        mode = ueye.uint()
        ueye.nRet = ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_GET_MODE, mode, ueye.sizeof(mode))
        return mode
    
    def turn_on_flash_low(self):
        mode = ueye.int(ueye.IO_FLASH_MODE_TRIGGER_LO_ACTIVE)
        return ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_SET_MODE, mode, ueye.sizeof(mode))
    
    def turn_on_flash_high(self):
        mode = ueye.int(ueye.IO_FLASH_MODE_TRIGGER_HI_ACTIVE)
        return ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_SET_MODE, mode, ueye.sizeof(mode))
    
    def get_flash_range(self):
        flash_params_min = ueye.IO_FLASH_PARAMS()
        flash_params_min.delay = ueye.int()
        flash_params_min.duration = ueye.double()
        ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_GET_PARAMS_MIN, flash_params_min, ueye.sizeof(flash_params_min))
        
        flash_params_max = ueye.IO_FLASH_PARAMS()
        flash_params_max.delay = ueye.int()
        flash_params_max.duration = ueye.double()
        ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_GET_PARAMS_MAX, flash_params_max, ueye.sizeof(flash_params_max))

        flash_params_inc = ueye.IO_FLASH_PARAMS()
        flash_params_inc.delay = ueye.int()
        flash_params_inc.duration = ueye.double()
        ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_GET_PARAMS_INC, flash_params_inc, ueye.sizeof(flash_params_inc))
        
        return flash_params_min, flash_params_max, flash_params_inc
        
    def get_flash_params(self):
        flash_params = ueye.IO_FLASH_PARAMS()
#         flash_params.delay = ueye.int()
#         flash_params.duration = ueye.double()
        ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_GET_PARAMS, flash_params, ueye.sizeof(flash_params))
        return flash_params
    def set_flash_params(self, delay, duration):
        flash_params = ueye.IO_FLASH_PARAMS()
        flash_params.s32Delay = ueye.int(delay)
        flash_params.u32Duration = ueye.uint(duration)
        return ueye.is_IO(self.h_cam, ueye.IS_IO_CMD_FLASH_SET_PARAMS, flash_params, ueye.sizeof(flash_params))
    
    def get_blacklevel_mode(self):
        mode = ueye.int()
        ueye.is_Blacklevel(self.h_cam, ueye.IS_BLACKLEVEL_CMD_GET_MODE, mode, ueye.sizeof((mode)))
        return mode
    def set_blacklevel_mode(self, mode):
        mode = ueye.int(mode)
        return ueye.is_Blacklevel(self.h_cam, ueye.IS_BLACKLEVEL_CMD_SET_MODE, mode, ueye.sizeof((mode)))
    def get_blacklevel(self):
        Level = ueye.int()
        ueye.is_Blacklevel(self.h_cam, ueye.IS_BLACKLEVEL_CMD_GET_OFFSET, Level, ueye.sizeof((Level)))
        return Level
    def set_blacklevel(self, Level):
        Level = ueye.int(Level)
        return ueye.is_Blacklevel(self.h_cam, ueye.IS_BLACKLEVEL_CMD_SET_OFFSET, Level, ueye.sizeof((Level)))

    def get_exposure(self): 
        EXPOSURE = ueye.double() ### in ms
        ueye.is_Exposure(self.h_cam, ueye.IS_EXPOSURE_CMD_GET_EXPOSURE, EXPOSURE, ueye.sizeof((EXPOSURE)))
        return EXPOSURE    
    def set_exposure(self, EXPOSURE):
        EXPOSURE = ueye.double(EXPOSURE) ### in ms
        return ueye.is_Exposure(self.h_cam, ueye.IS_EXPOSURE_CMD_SET_EXPOSURE, EXPOSURE, ueye.sizeof((EXPOSURE)))

    def capture_video(self, wait=False):
        wait_param = ueye.IS_WAIT if wait else ueye.IS_DONT_WAIT
        return ueye.is_CaptureVideo(self.h_cam, wait_param)

    def stop_video(self):
        return ueye.is_StopLiveVideo(self.h_cam, ueye.IS_FORCE_VIDEO_STOP)
    
    def freeze_video(self, wait=False):
        wait_param = ueye.IS_WAIT if wait else ueye.IS_DONT_WAIT
        return ueye.is_FreezeVideo(self.h_cam, wait_param)

    def set_colormode(self, colormode):
        check(ueye.is_SetColorMode(self.h_cam, colormode))
        
    def get_colormode(self):
        ret = ueye.is_SetColorMode(self.h_cam, ueye.IS_GET_COLOR_MODE)
        return ret
    
    def get_colordepth(self):
        pnCol = ueye.int()
        pnColMode = ueye.int()
        ret = ueye.is_GetColorDepth(self.h_cam, pnCol, pnColMode)
        return pnCol, pnColMode

    def get_format_list(self):
        count = ueye.UINT()
        check(ueye.is_ImageFormat(self.h_cam, ueye.IMGFRMT_CMD_GET_NUM_ENTRIES, count, ueye.sizeof(count)))
        format_list = ueye.IMAGE_FORMAT_LIST(ueye.IMAGE_FORMAT_INFO * count.value)
        format_list.nSizeOfListEntry = ueye.sizeof(ueye.IMAGE_FORMAT_INFO)
        format_list.nNumListElements = count.value
        check(ueye.is_ImageFormat(self.h_cam, ueye.IMGFRMT_CMD_GET_LIST,
                                  format_list, ueye.sizeof(format_list)))
        return format_list
